import * as XLSX from 'xlsx'
import * as XLSXS from 'xlsx-style'
import FileSaver from 'file-saver'

// 计算字符串中中文字符个数
function computeCnStr (str = '') {
  if (str === null) { str = '' }
  let cnNum = 0
  for (let i = 0; i < str.length; i++) {
    // escape对字符串进行编码，字符值大于 255 的以 %u**** 格式存储，而字符值大于 255 的恰好是非英文字符（一般是中文字符）
    if (escape(str[i]).indexOf('%u') === 0) {
      cnNum += 1
    }
  }
  return [cnNum, str.length - cnNum]
}

function getColWidth (excelData) {
  const list = JSON.parse(JSON.stringify(excelData.slice(1)))
  const maxl = []
  const f1 = 16
  const f2 = 9
  for (let i = 0; i < list.length; i++) {
    for (let j = 0; j < list[i].length; j++) {
      const cnEnNumArr = computeCnStr(list[i][j])
      const strLength = cnEnNumArr[0] * f1 + cnEnNumArr[1] * f2
      maxl[j] = Math.max(maxl[j] || 0, strLength || 0)
    }
  }
  return maxl.map(l => {
    return { wpx: l }
  })
}

function getRowHeight (excelData) {
  return excelData.map(() => {
    return { hpx: 30 }
  })
}

export function export2Excel (tableField, tableData, filename, fnws) {
  // 需要导出的数据
  const excelData = []
  excelData.push([filename]) // 标题
  excelData.push(tableField.map(item => { return item.label })) // 表头
  for (let i = 0; i < tableData.length; i++) { // 数据
    const row = []
    tableField.map(item => {
      row.push(tableData[i][item.keyCode])
    })
    excelData.push(row)
  }

  // 导出的excel文件名
  filename = filename + '.xlsx'

  // Excel第一个sheet的名称
  const name = 'Sheet1'
  const wb = XLSX.utils.book_new()
  const ws = XLSX.utils.aoa_to_sheet(excelData)
  XLSX.utils.book_append_sheet(wb, ws, name) // 将数据添加到工作薄

  // 设置标题行单元格合并 s即start, e即end, r即row, c即column
  ws['!merges'] = [
    { s: { r: 0, c: 0 }, e: { r: 0, c: tableField.length - 1 } }
  ]

  // 设置单元格宽度
  ws['!cols'] = getColWidth(excelData)
  // 设置单元格高度
  ws['!rows'] = getRowHeight(excelData)

  // 设置单元格其他样式，可以遍历全部单元格,进行样式设置
  if (fnws) {
    fnws(ws)
  }
  // 导出Excel, 注意这里用到的是XLSXS对象
  const wbout = XLSXS.write(wb, {
    bookType: 'xlsx',
    bookSST: false,
    type: 'binary'
  })
  FileSaver.saveAs(
    new Blob([s2ab(wbout)], {
      type: 'application/octet-stream'
    }),
    filename
  )
}

/**
 * 工具方法
 */
function s2ab (s) {
  var buf = new ArrayBuffer(s.length)
  var view = new Uint8Array(buf)
  for (var i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
  return buf
}
